/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.blitscreen.render 
{
	import com.bourre.error.IndexOutOfBoundsException;	
	import com.bourre.error.NullPointerException;	
	import com.bourre.error.IllegalStateException;	
	
	import flash.display.BitmapData;
	import flash.utils.getTimer;
	
	import com.blitscreen.render.RenderQueue;
	import com.bourre.collection.ArrayIterator;
	import com.bourre.collection.Iterable;
	import com.bourre.collection.Iterator;	

	/**
	 * @author Cédric Néhémie
	 */
	public class BasicRenderQueue implements RenderQueue, Iterable 
	{
		/**
		 * 
		 */
		protected var _oScreen : BitmapData;
		/**
		 * 
		 */
		protected var _aPasses : Array;
		
		/**
		 * 
		 */
		protected var _nLastRenderTime : Number;

		/**
		 * 
		 */
		public function BasicRenderQueue ()
		{
			_aPasses = new Array();
		}

		/**
		 * 
		 */
		public function render () : void
		{
			if( hasOutput() )
			{
				var i : Iterator = iterator();
				var output : BitmapData  = getOutput( );
				var ms : Number = getTimer();
							
				output.lock();
				while( i.hasNext() )
				{
					( i.next() as RenderPass ).render( output );
				}
				output.unlock();
				
				_nLastRenderTime = getTimer() - ms;
			}
		}
		
		/**
		 * @param 	pass <code>RenderPass</code> 
		 * @throws	IllegalStateException - The passed-in <code>RenderPass</code>
		 * 			object is already register in this <code>RenderQueue</code>
		 * 			object.
		 * @throws 	NullPointerException - The passed-in <code>pass</code>
		 * 			argument is <code>null</code>.
		 */
		public function add ( pass : RenderPass ) : void
		{
			if( pass == null )
			{
				throw new NullPointerException ( "The passed-in RenderPass argument is null." );
			}
			else if ( contains( pass ) )
			{
				throw new IllegalStateException ( "The passed-in RenderPass object is already register " +
												  "in this RenderQueue object." );
			}
			else			
			{
				_aPasses.push( pass );
			}
		}
		/**
		 * @param 	index	<code>Number</code>
		 * @param 	pass 	<code>RenderPass</code>
		 * @throws	IndexOutOfBoundsException - The passed-in <code>index</code>
		 * 			is not a valid index for that render queue.
		 * @throws	IllegalStateException - The passed-in <code>RenderPass</code>
		 * 			object is already register in this <code>RenderQueue</code>
		 * 			object.
		 * @throws 	NullPointerException - The passed-in <code>pass</code>
		 * 			argument is <code>null</code>.
		 */
		public function addAt ( index : uint, pass : RenderPass ) : void
		{
			if( isNaN( index ) )
			{
				throw new IndexOutOfBoundsException( "The passed-in index is not a valid index : " + index );
			}
			else if( pass == null )
			{
				throw new NullPointerException ( "The passed-in pass argument is null." );
			}
			else if ( contains( pass ) )
			{
				throw new IllegalStateException ( "The passed-in RenderPass object is already register " +
												  "in this RenderQueue object." );
			}
			else
			{
				_aPasses.splice( index, 0, pass );
			}
		}	
		/**
		 * @param pass
		 */
		public function remove ( pass : RenderPass ) : void
		{
			if( contains( pass ) )
			{
				_aPasses.splice( _aPasses.indexOf( pass ), 1 );
			}
		}
		/**
		 * @param index
		 */
		public function removeAt ( index : uint ) : void
		{
			if( index < size() )
			{
				_aPasses.splice( index, 1 );
			}
		}
		/**
		 * @return
		 */	
		public function size () : Number
		{
			return _aPasses.length;
		}
		/**
		 * @return
		 */
		public function iterator () : Iterator
		{
			return new ArrayIterator( _aPasses );
		}
		/**
		 * @param pass
		 * @return
		 */		
		public function contains ( pass : RenderPass ) : Boolean
		{
			return _aPasses.indexOf( pass ) != -1;
		}
		
		/**
		 * @param screen
		 */
		public function setOutput ( screen : BitmapData ) : void
		{
			_oScreen = screen;
		}
		/**
		 * @return
		 */
		public function getOutput () : BitmapData
		{
			return _oScreen;
		}		
		/**
		 * @return
		 */
		public function hasOutput () : Boolean
		{
			return _oScreen != null;
		}
		
		/**
		 * @return
		 */
		public function getLastRenderTime () : Number
		{
			return _nLastRenderTime;
		}
	}
}
